﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure;
using AzureReader.BLL;
using Microsoft.WindowsAzure.StorageClient;
using System.ServiceModel;
using System.ServiceModel.Syndication;
using System.Xml;

namespace FeedsReader
{
    public class WorkerRole : RoleEntryPoint
    {
        public override void Run()
        {
            // This is a sample worker implementation. Replace with your logic.
            Trace.WriteLine("FeedsReader entry point called", "Information");
            //  WAStorageManager.InitStorage();
while (true)
{
    CloudQueueMessage feedMsg = null;
    try
    {
        using (AzureReaderDataContext db = new AzureReaderDataContext())
        {
            feedMsg = FeedsQueueManager.GetFeedFromQueue();
            if (feedMsg != null)
            {
                string feedUrl = feedMsg.AsString;
                Feed mainFeed = (from f in db.Feeds
                                 where f.FeedUrl == feedUrl
                                 select f).FirstOrDefault();
                if (mainFeed == null)
                {
                    FeedsQueueManager.DeleteFeedFromQueue(feedMsg);
                    continue;
                }
                
                using (XmlReader reader = XmlReader.Create(feedUrl, new XmlReaderSettings() { ProhibitDtd = false }))
                {
                    SyndicationFeedFormatter formatter = SyndicationFormatterFactory.CreateFeedFormatter(reader);
                    formatter.ReadFrom(reader);
                    SyndicationFeed feed = formatter.Feed;

                    CloudBlobContainer feedItemsContainer = BlobManager.StoreFeedInfo(feedUrl, feed.Title.Text, feed.Description.Text);
                    foreach (SyndicationItem item in feed.Items)
                    {
                        string feedItemUrl = "";
                        if (item.Links.Count > 0)
                            feedItemUrl = item.Links.Where(l => l.RelationshipType == "alternate").FirstOrDefault().Uri.ToString();
                        else
                            feedItemUrl = item.BaseUri.ToString();

                        var fi = (from f in db.FeedItems
                                  where f.FeedItemUrl == feedItemUrl
                                  select f).FirstOrDefault();

                        if (fi != null)
                        {

                            if (fi.LastUpdatedTime != item.LastUpdatedTime)
                            {
                                UpdateItemBlobs(feedItemsContainer, item, fi);
                            }
                        }
                        else
                        {
                            AddNewFeedItem(db, mainFeed, feedItemsContainer, item, feedItemUrl, fi);
                        }
                        db.SubmitChanges();
                        UpdateUsers(fi, feed.Title.Text, db);
                        db.SubmitChanges();
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        Logger.LogException(ex);
    }
    finally
    {
        if (feedMsg != null)
            FeedsQueueManager.DeleteFeedFromQueue(feedMsg);
    }
    Thread.Sleep(5000);
}
        }

        private static FeedItem AddNewFeedItem(AzureReaderDataContext db, Feed mainFeed, CloudBlobContainer feedItemsContainer, SyndicationItem item, string feedItemUrl, FeedItem fi)
        {
            fi = new FeedItem();

            fi.FeedItemID = Guid.NewGuid();
            if (item.LastUpdatedTime.DateTime != DateTime.MinValue)
                fi.LastUpdatedTime = item.LastUpdatedTime.DateTime;
            if (item.Title != null)
                fi.Title = item.Title.Text;
            if (item.Authors.Count > 0)
                fi.Author = item.Authors[0].Name;
            if (item.Copyright != null)
                fi.Copyright = item.Copyright.Text;

            fi.Feed = mainFeed;
            fi.FeedItemUrl = feedItemUrl;
            if (item.PublishDate.DateTime != DateTime.MinValue)
                fi.PublishDate = item.PublishDate.DateTime;

            UpdateItemBlobs(feedItemsContainer, item, fi);
            db.FeedItems.InsertOnSubmit(fi);
            return fi;
        }

        private static void UpdateItemBlobs(CloudBlobContainer feedItemsContainer, SyndicationItem item, FeedItem fi)
        {

            if (item.Content != null)
                if (!string.IsNullOrEmpty((item.Content as TextSyndicationContent).Text))
                {
                    if (string.IsNullOrEmpty(fi.ContentBlobUri))
                        fi.ContentBlobUri = BlobManager.StoreFeedItemContentBlob(feedItemsContainer, fi.FeedItemID.ToString(), (item.Content as TextSyndicationContent).Text);
                    else
                        BlobManager.UpdateFeedItemContentBlob(feedItemsContainer, fi.ContentBlobUri,
                         (item.Content == null) ? "" : (item.Content as TextSyndicationContent).Text);
                }
                else
                    fi.ContentBlobUri = "";
            else
                fi.ContentBlobUri = "";


            if (item.Summary != null)
                if (!string.IsNullOrEmpty((item.Summary as TextSyndicationContent).Text))
                {
                    if (string.IsNullOrEmpty(fi.SummaryBlobUri))
                        fi.SummaryBlobUri = BlobManager.StoreFeedItemSummaryBlob(feedItemsContainer, fi.FeedItemID.ToString(), (item.Summary as TextSyndicationContent).Text);
                    else
                        BlobManager.UpdateFeedItemSummaryBlob(feedItemsContainer, fi.ContentBlobUri,
                         (item.Summary == null) ? "" : (item.Summary as TextSyndicationContent).Text);
                }
                else
                    fi.SummaryBlobUri = "";
            else
                fi.SummaryBlobUri = "";
        }
        void UpdateUsers(FeedItem fi, string feedTitle, AzureReaderDataContext db)
        {
            var subs = from s in db.FeedSubscriptions
                       where s.Feed.FeedUrl == fi.Feed.FeedUrl
                       select s;
            foreach (var sub in subs)
            {
            db.UnreadFeedItems_Insert(sub.SubscriptionID,fi.FeedItemID);
            }
            db.SubmitChanges();
        }
        public override bool OnStart()
        {
            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 12;

            // Get the factory configuration so that it can be edited
            DiagnosticMonitorConfiguration config = DiagnosticMonitor.GetDefaultInitialConfiguration();

            // Set scheduled transfer interval for infrastructure logs to 1 minute
            config.DiagnosticInfrastructureLogs.ScheduledTransferPeriod = System.TimeSpan.FromMinutes(1);

            // Specify a logging level to filter records to transfer
            config.DiagnosticInfrastructureLogs.ScheduledTransferLogLevelFilter = LogLevel.Error;

            // Set scheduled transfer interval for user's Windows Azure Logs to 1 minute
            config.Logs.ScheduledTransferPeriod = System.TimeSpan.FromMinutes(1);

            DiagnosticMonitor.Start("DiagnosticsConnectionString", config);


            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
            RoleEnvironment.Changing += RoleEnvironmentChanging;

            #region Setup CloudStorageAccount Configuration Setting Publisher

            // This code sets up a handler to update CloudStorageAccount instances when their corresponding
            // configuration settings change in the service configuration file.
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                // Provide the configSetter with the initial value
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

                RoleEnvironment.Changed += (sender, arg) =>
                {
                    if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                        .Any((change) => (change.ConfigurationSettingName == configName)))
                    {
                        // The corresponding configuration setting has changed, propagate the value
                        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                        {
                            // In this case, the change to the storage account credentials in the
                            // service configuration is significant enough that the role needs to be
                            // recycled in order to use the latest settings. (for example, the 
                            // endpoint has changed)
                            RoleEnvironment.RequestRecycle();
                        }
                    }
                };
            });
            #endregion

            return base.OnStart();
        }

        private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            // If a configuration setting is changing
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                // Set e.Cancel to true to restart this role instance
                e.Cancel = true;
            }
        }
    }
}
